package com.aplink.generic.widgets;

import java.util.ArrayList;

import android.annotation.TargetApi;
import android.content.pm.PackageManager.NameNotFoundException;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.adapter.ConfigAdapter;
import com.aplink.generic.adapter.RadiusFilter;
import com.aplink.generic.adapter.SelectionAdapter;
import com.aplink.generic.cache.ContentDataManager;
import com.aplink.generic.constant.type.ActionType;
import com.aplink.generic.constant.type.ListViewSelection;
import com.aplink.generic.database.SqlMethods;
import com.aplink.generic.dictionary.GenericDictionary;
import com.aplink.generic.google.maps.ui.LocationUtil;
import com.aplink.generic.interfaces.FragmentStateListener;
import com.aplink.generic.interfaces.OnGetObjProInfo;
import com.aplink.generic.interfaces.OnNotifyDataSetChanged;
import com.aplink.generic.interfaces.OnSearchListener;
import com.aplink.generic.pojo.ColumnSetting;
import com.aplink.generic.pojo.ContentData;
import com.aplink.generic.pojo.GenericAttribute;
import com.aplink.generic.pojo.GenericObject;
import com.aplink.generic.pojo.controlspec.ControlSpec;
import com.aplink.generic.pojo.controlspec.ListviewSpec;
import com.aplink.generic.util.Language;
import com.aplink.generic.util.LogUtil;
import com.aplink.generic.util.objectrule.Target;
import com.aplink.generic.util.objectrule.TargetCollection;
import com.aplink.generic.widgets.util.SwipeItemDeletion;
import com.aplink.generic.xmlparser.ColumnSettingParser;
import com.aplink.sg.R;

public class ApLinkListView extends ApLinkBaseView implements OnSearchListener,
		LocationUtil.CallBack, OnNotifyDataSetChanged, FragmentStateListener,
		OnItemClickListener {
	private ArrayList<ColumnSetting> columnSettings;
	private int headerIndex = 0;
	private final ListviewSpec listviewSpec;
	private ArrayList<GenericObject> mArrDeletes;
	private ArrayList<GenericObject> mArrInserts;
	private final ContentData mContentData;
	private final SparseArray<GenericObject> mDeleteObjects;
	private ArrayList<GenericObject> mGenericObjects;
	private final SparseArray<GenericObject> mInsertObjects;
	private ArrayList<GenericObject> mListMainObjects;
	private final ListView mListView;
	private ConfigAdapter mListViewAdapter;
	private final ListViewSelection mListViewSelection;
	private String mMappingName;

	private RadiusFilter mRadiusFilter;

	private final ArrayList<Integer> mSelectedPositions;

	private SelectionAdapter mSelectionAdapter;

	private RadioGroup radiusFilterGroup;

	private SwipeRefreshLayout swipeRefreshLayout;

	private TargetCollection targetCollection;

	public ApLinkListView(final GenericFragment dataEntryActivity,
			final ControlSpec controlSpec, final View view, Bundle bundle) {
		super(dataEntryActivity, controlSpec, view, bundle);
		this.mListView = (ListView) view;
		this.listviewSpec = (ListviewSpec) controlSpec;
		this.targetCollection = this.listviewSpec.getTargetCollection();
		this.mContentData = ContentDataManager.getInstance().get(
				this.listviewSpec.getContentDataID());
		this.targetCollection = this.listviewSpec.getTargetCollection();
		this.mInsertObjects = new SparseArray<GenericObject>();
		this.mDeleteObjects = new SparseArray<GenericObject>();
		this.mListViewSelection = this.listviewSpec.getListViewSelection();
		if (this.mListViewSelection != null) {
			if (!this.listviewSpec.getListViewSelection().equals(
					ListViewSelection.NONE)) {
				final SqlMethods sqlMethods = getGenericFragment()
						.getSqlMethods();
				final ContentData contentData = getGenericFragment()
						.getContentData();
				this.mListMainObjects = getGenericFragment().getDatabaseGet()
						.getList(contentData, sqlMethods.toString());
				this.mMappingName = this.listviewSpec.getDataObject() + "."
						+ this.listviewSpec.getMappingName();
			}
		}
		this.mArrDeletes = new ArrayList<GenericObject>();
		this.mArrInserts = new ArrayList<GenericObject>();
		this.mSelectedPositions = new ArrayList<Integer>();
	}

	@Override
	public void clear() {

	}

	@Override
	public void dataSetChanged() {
		if (getGenericFragment().getSearchView() != null) {
			getGenericFragment().getSearchView().setQueryHint(
					mListViewAdapter.getDisplayObjects().size() + " results");
		}
	}

	private ConfigAdapter generateConfigAdapter() {
		this.columnSettings = ColumnSettingParser.parse(getGenericFragment(),
				this.listviewSpec.getRptrdesignID());
		if (listviewSpec.isSwipeToRemove()) {
			SwipeItemDeletion mTouchListener = new SwipeItemDeletion(
					getApplicationContext(), mListView);
			return new ConfigAdapter(getGenericFragment(),
					this.mGenericObjects, this.columnSettings,
					this.listviewSpec.getRowItem(), mTouchListener);
		}
		return new ConfigAdapter(getGenericFragment(), this.mGenericObjects,
				this.columnSettings, this.listviewSpec.getRowItem());
	}

	public ArrayList<GenericObject> getArrDeletes() {
		return this.mArrDeletes;
	}

	public ArrayList<GenericObject> getArrInserts() {
		return this.mArrInserts;
	}

	@Override
	public GenericAttribute getAttribute() {
		return null;
	}

	public ContentData getContentData() {
		return this.mContentData;
	}

	public ArrayList<GenericObject> getDeleteList() {
		final ArrayList<GenericObject> arrayList = new ArrayList<GenericObject>();
		for (int i = 0; i < this.mDeleteObjects.size(); i++) {
			final int mainIndex = this.mDeleteObjects.keyAt(i);
			arrayList.add(this.mListMainObjects.get(mainIndex));
			this.mArrDeletes.add(this.mListMainObjects.get(mainIndex));
		}
		return arrayList;
	}

	public ConfigAdapter getGenericConfigAdapter() {
		return this.mListViewAdapter;
	}

	public ArrayList<GenericObject> getInsertList() {
		final ArrayList<GenericObject> arrayList = new ArrayList<GenericObject>();
		for (int i = 0; i < this.mInsertObjects.size(); i++) {
			final int mainIndex = this.mInsertObjects.keyAt(i);
			final GenericAttribute genericAttribute = GenericAttribute.obtain(
					this.mSelectionAdapter.getValue(mainIndex),
					this.listviewSpec.getMappingName());
			final boolean isForceRenew = this.mListViewSelection
					.equals(ListViewSelection.MULTIPLE_SELECTION);
			final GenericObject genericObject = getGenericFragment()
					.getMappingObject(isForceRenew);
			genericObject.put(this.listviewSpec.getDataObject() + "."
					+ this.listviewSpec.getMappingName(), genericAttribute);
			arrayList.add(genericObject);
			this.mArrInserts.add(genericObject);
			try {
				Thread.sleep(2000);
			} catch (final InterruptedException e) {
				e.printStackTrace();
			}
		}
		return arrayList;
	}

	@Override
	public GenericDictionary<String, GenericAttribute> getListAttributes() {
		final GenericDictionary<String, GenericAttribute> hashMap = new GenericDictionary<String, GenericAttribute>();
		if (!this.listviewSpec.getListViewSelection().equals(
				ListViewSelection.NONE)) {
			final SparseBooleanArray sparseBooleanArray = this.mListView
					.getCheckedItemPositions();
			for (int i = 0; i < this.mSelectionAdapter.getCount(); i++) {
				if (sparseBooleanArray.get(i)) {
					final GenericAttribute genericAttribute = GenericAttribute
							.obtain(this.mSelectionAdapter.getValue(i),
									this.listviewSpec.getMappingName());
					hashMap.put(this.listviewSpec.getDataObject() + "."
							+ this.listviewSpec.getMappingName(),
							genericAttribute);
				}
			}
		}
		return hashMap;
	}

	public ListViewSelection getListViewSelection() {
		return this.mListViewSelection;
	}

	public OnSearchListener getOnSearchListener() {
		return this;
	}

	@Override
	public ListView getView() {
		return this.mListView;
	}

	@Override
	public void handleLocationChange(Location location) {
		if (mRadiusFilter != null) {
			mRadiusFilter.setLocation(location);
			if (radiusFilterGroup != null) {
				RadioButton radioButton = (RadioButton) radiusFilterGroup
						.findViewById(radiusFilterGroup
								.getCheckedRadioButtonId());
				if (mRadiusFilter.getLocation() != null) {
					mRadiusFilter.filter(radioButton.getText());
				}
			}
		}
		if (location.getAccuracy() <= 10) {
			LocationUtil.getInstance().disconnect();
			LocationUtil.getInstance().dispose();
		}
	}

	private void handleSelection(final SelectionAdapter selectionAdapter) {
		if (this.mListMainObjects != null) {
			for (final GenericObject genericObject : this.mListMainObjects) {
				final String value = genericObject.getValue(this.mMappingName);
				if (!TextUtils.isEmpty(value)) {
					final int index = selectionAdapter.getPosition(value);
					if (index != -1) {
						this.mListView.setItemChecked(index, true);
						this.mSelectedPositions.add(index);
					}
				}
			}
		}
	}

	private TextView swipeToRefresh;

	private void handleSwipeRefreshLayout() {
		swipeToRefresh = (TextView) getActivity().findViewById(
				R.id.swipeToRefreshText);
		if (!TextUtils.isEmpty(listviewSpec.getSwipeToRefreshTitle())) {
			swipeToRefresh.setText(Language.getInstance().get(
					listviewSpec.getSwipeToRefreshTitle()));
		}
		swipeRefreshLayout.setColorSchemeResources(
				android.R.color.holo_blue_bright,
				android.R.color.holo_green_light,
				android.R.color.holo_orange_light,
				android.R.color.holo_red_light);
		swipeRefreshLayout
				.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
					@Override
					public void onRefresh() {
						swipeRefreshLayout.setRefreshing(true);
						swipeRefreshLayout.setEnabled(!swipeRefreshLayout
								.isRefreshing());
						getActivity().getActionBar().show();
						swipeToRefresh.setVisibility(View.INVISIBLE);
						getGenericFragment().getEventHandler().sendAction(
								ActionType.DOWNLOAD);
					}
				});
		swipeRefreshLayout.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(final View v, final MotionEvent event) {
				if (swipeRefreshLayout.onTouchEvent(event)) {
					if (!swipeRefreshLayout.isRefreshing()) {
						getActivity().getActionBar().hide();
						swipeToRefresh.setVisibility(View.VISIBLE);
					}
				} else {
					getActivity().getActionBar().show();
					swipeToRefresh.setVisibility(View.INVISIBLE);
				}
				return false;
			}
		});

		mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
			@Override
			public void onScrollStateChanged(AbsListView view, int scrollState) {

			}

			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				int topRowVerticalPosition = (mListView == null || mListView
						.getChildCount() == 0) ? 0 : mListView.getChildAt(0)
						.getTop();
				swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
			}
		});
	}

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
	@Override
	protected void initViewProperties() {
		swipeRefreshLayout = (SwipeRefreshLayout) getActivity().findViewById(
				R.id.SwipeRefreshLayout);
		if (listviewSpec.isSwipeToRefresh()) {
			handleSwipeRefreshLayout();
		} else {
			if (swipeRefreshLayout != null) {
				swipeRefreshLayout.setEnabled(false);
			}
		}

		if (!TextUtils.isEmpty(listviewSpec.getEmptyMessage())) {
			TextView textView = (TextView) getActivity().findViewById(
					android.R.id.empty);
			mListView.setEmptyView(textView);
			textView.setTag(R.id.TEXT_ENGLISH, listviewSpec.getEmptyMessage());
			textView.setText(Language.getInstance().get(
					listviewSpec.getEmptyMessage()));

			textView.setCompoundDrawablesWithIntrinsicBounds(0,
					listviewSpec.getEmptyIconID(), 0, 0);
		}

		if ((this.listviewSpec.getListViewSelection() != null)
				&& !this.listviewSpec.getListViewSelection().equals(
						ListViewSelection.NONE)) {
			this.mListView.setChoiceMode(this.listviewSpec
					.getListViewSelection().getValue());
		}
		if (!listviewSpec.getContextMenus().isEmpty()) {
			mListView.setTag(R.id.CONTEXT_MENU, listviewSpec.getContextMenus());
			getGenericFragment().registerForContextMenu(mListView);
		}

		radiusFilterGroup = (RadioGroup) getActivity().findViewById(
				R.id.SEARCH_RADIUS);
		if (radiusFilterGroup != null) {
			radiusFilterGroup
					.setOnCheckedChangeListener(new OnCheckedChangeListener() {

						@Override
						public void onCheckedChanged(RadioGroup group,
								int checkedId) {
							RadioButton radioButton = (RadioButton) group
									.findViewById(checkedId);
							if (mRadiusFilter.getLocation() != null) {
								mRadiusFilter.filter(radioButton.getText());
							}
						}
					});
		}
	}

	@Override
	public void languageChanged() {

	}

	@Override
	protected void loadBindingObject() {
		SqlMethods whereClause = SqlMethods.getInstance();
		if (!listviewSpec.isLoadAll()) {
			whereClause = getGenericFragment().getSqlMethods();
		}
		this.mGenericObjects = getDatabaseGet().getList(this.mContentData,
				whereClause == null ? null : whereClause.toString());

		if (this.listviewSpec.getListViewSelection().equals(
				ListViewSelection.NONE)) {
			this.mListViewAdapter = generateConfigAdapter();
			this.mListView.setAdapter(this.mListViewAdapter);
		} else if (this.listviewSpec.getListViewSelection().equals(
				ListViewSelection.SINGLE_SELECTION)) {
			this.mSelectionAdapter = new SelectionAdapter(
					getApplicationContext(),
					android.R.layout.simple_list_item_single_choice,
					this.mGenericObjects, this.listviewSpec);
			this.mListView.setAdapter(this.mSelectionAdapter);
			handleSelection(this.mSelectionAdapter);
		} else if (this.listviewSpec.getListViewSelection().equals(
				ListViewSelection.MULTIPLE_SELECTION)) {
			this.mSelectionAdapter = new SelectionAdapter(
					getApplicationContext(),
					android.R.layout.simple_list_item_multiple_choice,
					this.mGenericObjects, this.listviewSpec);
			this.mListView.setAdapter(this.mSelectionAdapter);
			handleSelection(this.mSelectionAdapter);
		}
	}

	@Override
	protected void loadDefaultObject() {
		this.mGenericObjects = getDatabaseGet()
				.getList(this.mContentData, null);
		if (this.mGenericObjects != null) {
			if (this.listviewSpec.getListViewSelection().equals(
					ListViewSelection.NONE)) {
				this.mListViewAdapter = generateConfigAdapter();
				this.mListView.setAdapter(this.mListViewAdapter);
			} else if (this.listviewSpec.getListViewSelection().equals(
					ListViewSelection.SINGLE_SELECTION)) {
				this.mSelectionAdapter = new SelectionAdapter(
						getApplicationContext(),
						android.R.layout.simple_list_item_single_choice,
						this.mGenericObjects, this.listviewSpec);
				this.mListView.setAdapter(this.mSelectionAdapter);
			} else if (this.listviewSpec.getListViewSelection().equals(
					ListViewSelection.MULTIPLE_SELECTION)) {
				this.mSelectionAdapter = new SelectionAdapter(
						getApplicationContext(),
						android.R.layout.simple_list_item_multiple_choice,
						this.mGenericObjects, this.listviewSpec);
				this.mListView.setAdapter(this.mSelectionAdapter);
			}
		}
	}

	@Override
	public void notifyDataSetChanged() {
		super.notifyDataSetChanged();
		if (listviewSpec.isSwipeToRefresh()) {
			swipeRefreshLayout.setRefreshing(false);
			swipeRefreshLayout.setEnabled(!swipeRefreshLayout.isRefreshing());
		}
		dataSetChanged();
	}

	@Override
	public void onCreate(Bundle bundle) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onItemClick(AdapterView<?> arg0, View view, int index, long id) {
		if (!ApLinkListView.this.listviewSpec.getTargetCollection().isEmpty()) {
			final String fullClassName = null;
			try {
				final GenericObject genericObject = ApLinkListView.this.mListViewAdapter
						.getDisplayObjects().get(
								index - ApLinkListView.this.headerIndex);
				final Target targetActivity = ApLinkListView.this.targetCollection
						.getTargetClass(genericObject);
				ApLinkListView.this.getGenericFragment().startActivity(
						targetActivity.getTargetClass(),
						targetActivity.getPassingValue(), genericObject);
			} catch (final ClassNotFoundException e) {
				LogUtil.error(fullClassName + " is not found",
						"List view item click", getClass());
			} catch (final NameNotFoundException e) {
				e.printStackTrace();
			}
		} else {
			if (ApLinkListView.this.mListViewSelection != null) {
				final SparseBooleanArray sparseBooleanArray = ApLinkListView.this.mListView
						.getCheckedItemPositions();
				if (ApLinkListView.this.mListViewSelection
						.equals(ListViewSelection.MULTIPLE_SELECTION)) {
					final GenericObject genericObject = ApLinkListView.this.mSelectionAdapter
							.getObject(index);
					if (sparseBooleanArray.get(index)) {
						ApLinkListView.this.mInsertObjects.put(index,
								genericObject);
						if (ApLinkListView.this.mDeleteObjects.get(index) != null) {
							ApLinkListView.this.mDeleteObjects.remove(index);
						}
					} else {
						ApLinkListView.this.mDeleteObjects.put(index,
								genericObject);
						if (ApLinkListView.this.mInsertObjects.get(index) != null) {
							ApLinkListView.this.mInsertObjects.remove(index);
						}
					}
				} else if (ApLinkListView.this.mListViewSelection
						.equals(ListViewSelection.SINGLE_SELECTION)) {
					final GenericObject genericObject = ApLinkListView.this.mSelectionAdapter
							.getObject(index);
					ApLinkListView.this.mInsertObjects.clear();
					ApLinkListView.this.mDeleteObjects.clear();
					ApLinkListView.this.mInsertObjects
							.put(index, genericObject);
				}
			}
		}
	}

	@Override
	public void onPause() {
		if (radiusFilterGroup != null) {
			LocationUtil.getInstance().disconnect();
		}
	}

	@Override
	public void onResume() {
		if (radiusFilterGroup != null) {
			LocationUtil.getInstance()
					.getDefaultLocationService(this, getApplicationContext())
					.connect();
		}
	}

	@Override
	public void onSearch(final ArrayList<String> searchFields,
			final String queryString) {
		this.mListViewAdapter.setSearchFileds(searchFields);
		this.mListViewAdapter.getFilter().filter(queryString);
	}

	@Override
	public void onSearchClose() {
		this.mListViewAdapter.setSearchFileds(null);
		this.mListViewAdapter.getFilter().filter(null);
	}

	@Override
	public void onStart() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStop() {
		// TODO Auto-generated method stub

	}

	public void setArrDeletes(final ArrayList<GenericObject> arrDeletes) {
		this.mArrDeletes = arrDeletes;
	}

	public void setArrInserts(final ArrayList<GenericObject> arrInserts) {
		this.mArrInserts = arrInserts;
	}

	@Override
	protected void setEventListener() {
		mListView.setOnItemClickListener(this);
		if (mListViewAdapter != null) {
			mListViewAdapter.setDataSetChanged(this);
		}
		mRadiusFilter = new RadiusFilter(null, mListViewAdapter);
		getGenericFragment().setFragmentStateListener(this);
	}

	public void setGenericConfigAdapter(final ConfigAdapter genericConfigAdapter) {
		this.mListViewAdapter = genericConfigAdapter;
	}

	@Override
	public void setObjPropInfoTemp(final OnGetObjProInfo getObjProInfo) {
		throw new UnsupportedOperationException(this.getClass().getSimpleName()
				+ " is not support this method");
	}

	@Override
	public void setOnClickListener(final OnClickListener onClickListener) {
		throw new UnsupportedOperationException(this.getClass().getSimpleName()
				+ " is not support this method");
	}
}
